import json
import os
from enum import Enum
from typing import Any

import requests
from pydantic import BaseModel, Field, ValidationError
from rich.console import Console
from requests.exceptions import RequestException, HTTPError, ConnectionError, Timeout
import time

console = Console()
# 配置参数 
BASE_URL = os.getenv("MCP_BASE_URL", "http://127.0.0.1:8002")
BASE_DIR = os.getenv("MCP_BASE_DIR", "/opt/copilot/semantics/mcp/template")
REQUEST_TIMEOUT = 30  # 请求超时时间(秒)
MAX_RETRY_COUNT = 3  # API请求重试次数
RETRY_DELAY = 2  # 重试延迟(秒)
SERVICE_WAIT_TIMEOUT = 60  # 服务等待超时时间(秒)
HTTP_OK = 200  # HTTP 成功状态码


class AppType(str, Enum):
    """应用中心应用类型"""
    FLOW = "flow"
    AGENT = "agent"


class AppLink(BaseModel):
    """App的相关链接"""
    title: str = Field(description="链接标题")
    url: str = Field(..., description="链接地址", pattern=r"^(https|http)://.*$")


class PermissionType(str, Enum):
    """权限类型"""
    PROTECTED = "protected"
    PUBLIC = "public"
    PRIVATE = "private"


class AppPermissionData(BaseModel):
    """应用权限数据结构"""
    type: PermissionType = Field(
        default=PermissionType.PRIVATE,
        alias="visibility",
        description="可见性（public/private/protected）",
    )
    users: list[str] | None = Field(
        None,
        alias="authorizedUsers",
        description="附加人员名单（如果可见性为部分人可见）",
    )


class AppFlowInfo(BaseModel):
    """应用工作流数据结构"""
    id: str = Field(..., description="工作流ID")
    name: str = Field(..., description="工作流名称")
    description: str = Field(..., description="工作流简介")
    debug: bool = Field(..., description="是否经过调试")


class AppData(BaseModel):
    """应用信息数据结构"""
    app_type: AppType = Field(..., alias="appType", description="应用类型")
    icon: str = Field(default="", description="图标")
    name: str = Field(..., max_length=20, description="应用名称")
    description: str = Field(..., max_length=150, description="应用简介")
    links: list[AppLink] = Field(default=[], description="相关链接", max_length=5)
    first_questions: list[str] = Field(default=[], alias="recommendedQuestions", description="推荐问题", max_length=3)
    history_len: int = Field(3, alias="dialogRounds", ge=1, le=10, description="对话轮次（1～10）")
    permission: AppPermissionData = Field(
        default_factory=lambda: AppPermissionData(authorizedUsers=None),
        description="权限配置",
    )
    workflows: list[AppFlowInfo] = Field(default=[], description="工作流信息列表")
    mcp_service: list[str] = Field(default=[], alias="mcpService", description="MCP服务id列表")


class ApiClient:
    """API请求客户端封装"""

    def __init__(self, base_url: str, *, verify_ssl: bool = False) -> None:
        """
        初始化API客户端。
        Args:
            base_url: API的基础URL
            verify_ssl: 是否验证SSL证书（requests参数）
        """
        self.base_url = base_url
        self.verify_ssl = verify_ssl  # 用于控制requests的SSL验证
        # 创建requests会话，复用连接
        self.session = requests.Session()
        self.api_key = os.getenv("OI_API_KEY")
        if self.api_key is None:
            self.api_key = ""

    def close(self) -> None:
        """关闭客户端会话"""
        self.session.close()

    def request(self, method: str, path: str, **kwargs: Any) -> dict[str, Any]:
        """
        带重试机制的同步API请求（
        Args:
            method: HTTP方法（GET/POST/DELETE等）
            path: API路径
            **kwargs: 传递给requests的参数（如json、params等）
        Returns:
            API响应的JSON数据
        Raises:
            RequestException: 当请求失败时
        """
        url = f"{self.base_url}{path}"
        # 添加超时参数，确保不无限等待
        kwargs.setdefault("timeout", REQUEST_TIMEOUT)
        # 控制SSL验证
        kwargs.setdefault("verify", self.verify_ssl)
        headers = kwargs.pop("headers", {})
        # 从环境变量OI_KEY获取API密钥
        api_key = os.getenv("OI_KEY")
        if api_key:
            headers["Authorization"] = f"Bearer {api_key}"
        kwargs["headers"] = headers
        for retry in range(MAX_RETRY_COUNT):
            try:
                # 同步发送请求
                response = self.session.request(method, url, **kwargs)
                response.raise_for_status()  # 触发HTTP错误（如4xx/5xx）
                return response.json()  # 解析JSON响应

            # 捕获requests相关异常
            except (HTTPError, ConnectionError, Timeout) as e:
                console.print(f"API请求失败(第{retry + 1}/{MAX_RETRY_COUNT}次) - {method} {url}: {e}")
                if retry < MAX_RETRY_COUNT - 1:
                    time.sleep(RETRY_DELAY)

        msg = f"API请求多次失败: {method} {url}"
        raise RuntimeError(msg)


def create_mcp_server(api_client: ApiClient, mcp_config: dict) -> str:
    """创建或更新MCP服务状态"""
    console.print("创建MCP服务")
    response = api_client.request("POST", "/api/mcp/", json=mcp_config)

    service_id = response.get("result", {}).get("serviceId")
    if not service_id:
        msg = "创建MCP服务未返回有效的serviceId"
        raise RuntimeError(msg)

    console.print("MCP服务创建成功，service_id: ", service_id)
    return service_id


def wait_for_mcp_service(api_client: ApiClient, service_id: str) -> dict[str, Any]:
    """
    等待MCP服务就绪
    Args:
        api_client: API客户端实例
        service_id: MCP服务ID
    Returns:
        服务信息字典
    Raises:
        RuntimeError: 服务超时未就绪
    """
    console.print(f"等待MCP服务 {service_id} 就绪: ")

    for elapsed in range(SERVICE_WAIT_TIMEOUT):
        try:
            service = query_mcp_server(api_client, service_id)
            if service and service.get("status") == "ready":
                console.print(f"MCP服务 {service_id} 已就绪 (耗时 {elapsed} 秒)")
                return service

            time.sleep(1)  # 同步等待1秒

        except (RequestException, RuntimeError) as e:
            console.print(f"查询服务状态失败: {e}，将继续等待")

    msg = f"MCP服务 {service_id} 等待超时 ({SERVICE_WAIT_TIMEOUT}秒) 未就绪"
    raise RuntimeError(msg)


def delete_mcp_server(api_client: ApiClient, server_id: str) -> dict[str, Any]:
    """删除MCP服务"""
    console.print(f"删除MCP服务: {server_id}")
    return api_client.request("DELETE", f"/api/mcp/{server_id}")


def query_mcp_server(api_client: ApiClient, mcp_id: str) -> dict[str, Any] | None:
    """查询MCP服务状态"""
    console.print(f"查询MCP服务状态: {mcp_id}")
    response = api_client.request("GET", "/api/mcp/" + mcp_id)

    if response.get("code") != HTTP_OK:
        msg = f"查询MCP服务失败: {response.get('message', '未知错误')}"
        raise RuntimeError(msg)

    return response.get("result", {})


def install_mcp_server(api_client: ApiClient, mcp_id: str) -> dict[str, Any] | None:
    """安装mcp服务"""
    console.print(f"安装MCP服务: {mcp_id}")
    response = api_client.request("GET", "/api/mcp/" + mcp_id)

    if response.get("code") != HTTP_OK:
        msg = f"查询MCP服务失败: {response.get('message', '未知错误')}"
        raise RuntimeError(msg)

    service = response.get("result", {})
    if service.get("serviceId") == mcp_id:
        console.print("MCP服务 ", mcp_id, " 状态: ", service.get("status"))
        if service.get("status") != "ready":
            console.print("开始安装MCP服务", mcp_id)
            return api_client.request("POST", f"/api/mcp/{mcp_id}/install")
    return None


def activate_mcp_server(api_client: ApiClient, mcp_id: str) -> dict[str, Any]:
    """激活mcp服务"""
    console.print("激活MCP服务: ", mcp_id)
    return api_client.request("POST", f"/api/mcp/{mcp_id}", json={"active": "true"})


def deploy_app(api_client: ApiClient, app_id: str) -> dict[str, Any]:
    """发布应用"""
    console.print("发布应用: ", app_id)
    return api_client.request("POST", f"/api/app/{app_id}", json={})


def call_app_api(api_client: ApiClient, appdata: AppData) -> str:
    """创建智能体应用agent"""
    try:
        app_data_dict = appdata.model_dump(by_alias=True)
        console.print("创建应用数据: ", json.dumps(app_data_dict, ensure_ascii=False))

        response = api_client.request("POST", "/api/app", json=app_data_dict)
        app_id = response.get("result", {}).get("appId")

        if not app_id:
            msg = "创建应用未返回有效的appId"
            raise RuntimeError(msg)

        console.print("应用创建成功，app_id: ", app_id)
    except ValidationError as e:
        msg = f"应用数据验证失败: {e!s}"
        raise ValueError(msg) from e
    else:
        return app_id


def get_app_list(api_client: ApiClient) -> str:
    """查询智能体应用agent list"""
    try:
        response = api_client.request("GET", "/api/app")
        return str(response)

    except ValidationError as e:
        msg = f"应用数据验证失败: {e!s}"
        raise ValueError(msg) from e


def create_agent_api(api_client: ApiClient, service_id: str) -> None:
    """创建agent流程：处理单个MCP服务并创建应用"""
    # 安装并等待服务就绪
    install_mcp_server(api_client, service_id)
    mcp_server = wait_for_mcp_service(api_client, service_id)

    # 激活服务（如果未激活）
    if not mcp_server.get("isActive"):
        activate_mcp_server(api_client, service_id)

    # 创建应用数据
    app_name = mcp_server.get("name", f"agent_{service_id[:6]}")[:20]
    app_desc = mcp_server.get("description", f"Auto-created agent for {service_id}")[:150]

    app_data = AppData(
        appType=AppType.AGENT,
        description=app_desc,
        dialogRounds=3,
        icon="",
        mcpService=[service_id],
        name=app_name,
        permission=AppPermissionData(visibility=PermissionType.PUBLIC, authorizedUsers=[]),
    )

    # 创建并发布应用
    app_id = call_app_api(api_client, app_data)
    deploy_app(api_client, app_id)
    console.print("Agent创建流程完成")


def comb_create(api_client: ApiClient, config: dict) -> str:
    """组合创建流程：安装多个MCP服务并创建应用"""
    # 处理所有MCP服务
    for service_id in config['mcpService']:
        install_mcp_server(api_client, service_id)
        mcp_server = wait_for_mcp_service(api_client, service_id)

        # 激活服务（如果未激活）
        if not mcp_server.get("isActive"):
            activate_mcp_server(api_client, service_id)

    # 创建并发布应用
    app_data = AppData(**config)
    app_id = call_app_api(api_client, app_data)
    deploy_app(api_client, app_id)
    console.print("组合创建流程完成")
    return app_id


def delete_agent_api(api_client: ApiClient, agent_id: str) -> dict[str, Any]:
    """删除agent服务"""
    console.print("删除agent服务: ", agent_id)
    return api_client.request("DELETE", f"/api/app/{agent_id}")
